#include "tan_byteobject.h"
#include "tan_alloc.h"

#include "tan_nbobject.h"

static const TAN_INT8* tan_byte_typename = "byte";

TanObject* Tan_Byte_Copy(TanObject* byte)
{
	if (strcmp(byte->object_type, tan_byte_typename) == 0)
	{
		return Tan_Byte(Tan_Byte_cast(byte)->var_byte);
	}
	else
	{
		Tan_RepError(false, "Not of type 'byte'.", byte);
	}
	return Tan_Byte(false);
}

static void byte_delete(TanObject* oneself)
{
	free(Tan_Byte_cast(oneself));
}

static void	byte_clear(TanObject* oneself)
{
	Tan_Byte_cast(oneself)->var_byte = 0;
}

static void byte_repr(TanObject* oneself)
{
	printf("%c", Tan_Byte_cast(oneself)->var_byte);
}

static Tan_bool byte_compare(TanObject* oneself, TanObject* other, TanCompareType type)
{
	TanByteObject* self_object = Tan_Byte_cast(oneself);

	if (!other)
	{
		Tan_RepError(false, "Cannot perform comparison operation, right value is null.", oneself);
		return Tan_false;
	}

	if (strcmp(other->object_type, tan_byte_typename) == 0)
	{
		TanByteObject* other_object = Tan_Byte_cast(other);
		if (type == Tan_compare_equal && self_object->var_byte == other_object->var_byte)
			return Tan_true;
		else if (type == Tan_compare_noequal && self_object->var_byte != other_object->var_byte)
			return Tan_true;
		else if (type == Tan_compare_greaterThan && self_object->var_byte > other_object->var_byte)
			return Tan_true;
		else if (type == Tan_compare_lessThan && self_object->var_byte < other_object->var_byte)
			return Tan_true;
		else if (type == Tan_compare_grea_equal && self_object->var_byte >= other_object->var_byte)
			return Tan_true;
		else if (type == Tan_compare_less_equal && self_object->var_byte <= other_object->var_byte)
			return Tan_true;
		else
		{
			Tan_RepError(false, "This operator is not supported.", oneself);
		}
	}
	else if (strcmp(other->object_type, "number") == 0)
	{
		TanNumberObject* other_object = Tan_Number_cast(other);
		if (type == Tan_compare_equal && self_object->var_byte == other_object->number)
			return Tan_true;
		else if (type == Tan_compare_noequal && self_object->var_byte != other_object->number)
			return Tan_true;
		else if (type == Tan_compare_greaterThan && self_object->var_byte > other_object->number)
			return Tan_true;
		else if (type == Tan_compare_lessThan && self_object->var_byte < other_object->number)
			return Tan_true;
		else if (type == Tan_compare_grea_equal && self_object->var_byte >= other_object->number)
			return Tan_true;
		else if (type == Tan_compare_less_equal && self_object->var_byte <= other_object->number)
			return Tan_true;
		else
		{
			Tan_RepError(false, "This operator is not supported.", oneself);
		}
	}
	else
	{
		Tan_RepError(false, 
			"The 'byte' type does not support operator operations other than 'byte' and 'number'.", 
			oneself);
	}
	return Tan_false;
}

static TanObjectType byte_object_type =
{
	Tan_Byte_Copy,		// type_copy
	byte_delete,		// type_delete
	byte_clear,			// type_clear
	byte_repr,			// var_repr
	byte_compare,		// var_coompare
	0,	// var_assign
	0,		// var_operation
	0,
	0				// next
};

static void byte_assign(TanObject** oneself, TanObject* other, TanAssignType type)
{
	TanByteObject* self_object = Tan_Byte_cast(*oneself);

	if (!other)
	{
		Tan_RepError(false, "Cannot perform comparison operation, right value is null.", *oneself);
	}

	if (strcmp(other->object_type, tan_byte_typename) == 0)
	{
		TanByteObject* other_object = Tan_Byte_cast(other);
		if (type == Tan_assign_equal)
			self_object->var_byte = other_object->var_byte;
		else if (type = Tan_assign_sum_equal)
		{
			TAN_INT32 sum = (TAN_INT32)(self_object->var_byte) + (TAN_INT32)(other_object->var_byte);
			if (sum > 127 || sum < 0)
			{
				TanNumberObject* number = Tan_Number(sum);
				Tan_Var_cast(number)->var_req = Tan_Var_cast(*oneself)->var_req;
				Tan_Var_cast(number)->var_size = Tan_Var_cast(*oneself)->var_size;
				free(*oneself);
				*oneself = number;
			}
			else
			{
				self_object->var_byte += other_object->var_byte;
			}
		}
		else if (type == Tan_assign_dif_equal)
		{
			TAN_INT32 dif = (TAN_INT32)(self_object->var_byte) - (TAN_INT32)(other_object->var_byte);
			if (dif > 127 || dif < 0)
			{
				TanNumberObject* number = Tan_Number(dif);
				Tan_Var_cast(number)->var_req = Tan_Var_cast(*oneself)->var_req;
				Tan_Var_cast(number)->var_size = Tan_Var_cast(*oneself)->var_size;
				free(*oneself);
				*oneself = number;
			}
			else
			{
				self_object->var_byte -= other_object->var_byte;
			}
		}
		else if (type == Tan_assign_mul_equal)
		{
			TAN_INT32 mul = (TAN_INT32)(self_object->var_byte) * (TAN_INT32)(other_object->var_byte);
			if (mul > 127 || mul < 0)
			{
				TanNumberObject* number = Tan_Number(mul);
				Tan_Var_cast(number)->var_req = Tan_Var_cast(*oneself)->var_req;
				Tan_Var_cast(number)->var_size = Tan_Var_cast(*oneself)->var_size;
				free(*oneself);
				*oneself = number;
			}
			else
			{
				self_object->var_byte *= other_object->var_byte;
			}
		}
		else if (type == Tan_assign_div_equal)
		{
			TAN_INT32 div = (TAN_INT32)(self_object->var_byte) / (TAN_INT32)(other_object->var_byte);
			if (div > 127 || div < 0)
			{
				TanNumberObject* number = Tan_Number(div);
				Tan_Var_cast(number)->var_req = Tan_Var_cast(*oneself)->var_req;
				Tan_Var_cast(number)->var_size = Tan_Var_cast(*oneself)->var_size;
				free(*oneself);
				*oneself = number;
			}
			else
			{
				self_object->var_byte *= other_object->var_byte;
			}
		}
		else if (type == Tan_assign_sum_sum)
		{
			TAN_INT32 ssm = ((TAN_INT32)(self_object->var_byte)) + 1;
			if (ssm > 127 || ssm < 0)
			{
				TanNumberObject* number = Tan_Number(ssm);
				Tan_Var_cast(number)->var_req = Tan_Var_cast(*oneself)->var_req;
				Tan_Var_cast(number)->var_size = Tan_Var_cast(*oneself)->var_size;
				free(*oneself);
				*oneself = number;
			}
			else
			{
				self_object->var_byte++;
			}
		}
		else if (type == Tan_assign_dif_dif)
		{
			TAN_INT32 ddf = ((TAN_INT32)(self_object->var_byte)) + 1;
			if (ddf > 127 || ddf < 0)
			{
				TanNumberObject* number = Tan_Number(ddf);
				Tan_Var_cast(number)->var_req = Tan_Var_cast(*oneself)->var_req;
				Tan_Var_cast(number)->var_size = Tan_Var_cast(*oneself)->var_size;
				free(*oneself);
				*oneself = number;
			}
			else
			{
				self_object->var_byte--;
			}
		}
	}
	else if (strcmp(other->object_type, "number") == 0)
	{
	}
	else
	{
	}
}

TanObject* Tan_Byte(TAN_INT8 byte)
{
	TanByteObject* var_byte = Tan_AllocObject_Memset(sizeof(TanByteObject));

	var_byte->var_byte = byte;
	Tan_Object_cast(var_byte)->object_type = tan_byte_typename;
	Tan_Var_cast(var_byte)->var_req = 1;
	Tan_Var_cast(var_byte)->var_size = 1;
	Tan_Object_cast(var_byte)->object_set = &byte_object_type;

}


